<?php
defined('APP') or die('Restricted access');
class Database 
{
    private         $_conn_id;
    private         $_query;
    private         $_result;
    private			$_models;
    private 		$_namequote		= '`';
    private 		$_valuequote	= '"';
    
    /**
    * Contructor
    */
    function __construct()
    { 
        $this->connect();
        $this->selectdb();
		$this->setutf8();
        $this->_model = array();
    }
    
    /**
    * Destructor
    */
    function __destruct()
    {
        $this->disconnect();
        unset($this->_conn_id);
    }
    
    /**
    * Connect to databases
    */
    private function connect()
    {
        $this->_conn_id = @mysql_connect(DB_HOST, DB_USER, DB_PASS) or $this->show_error('Can\'t connect to server');
    }
    
    /**
    * Disconnect to databases
    **/
    private function disconnect()
    {
        $result = false;
        if (is_resource($this->_conn_id)) {
            $return = @mysql_close($this->_conn_id);
        }
        return $result;
    }
   
   /**
    * Select a database for using later.
    **/
    private function selectdb()
    {
        return @mysql_select_db(DB_NAME, $this->_conn_id) or $this->show_error('Database not found!!!'); 
    }
	
	/**
    * Set UTF8 connection.
    **/
	private function setutf8()
	{
		return @mysql_query("SET NAMES 'utf8'");
	}
    
    /*
     * Show list tables
     */
    public function get_tables()
    {
    	$tables = array();
    	$this->set_query("SHOW TABLES");
    	$objects = $this->get_object_list();
    	if($objects)
    	{
    		foreach ($objects as $object)
    		{
    			$names = get_object_vars($object);
    			foreach ($names as $key => $val){
    				$tables[] = $val;
    			}
    		}
    	}
    	return $tables;
    }
    
    /**
    * Set SQL query for later using.
    **/
    function set_query($query = '')
    {
        if($query != '')
            $this->_query = $query;
        else
            $this->show_error('Invalid SQL String!!!');
    }
    
    /**
    * Get SQL query is storing.
    **/
    function get_query()
    {
        return $this->_query;
    }
    
    /**
    * Make query string is clearly
    **/
    function parse_query($text)
    {
        $result = mysql_real_escape_string( $text, $this->_conn_id );
        return $result;
    }
    
    /**
    * Execute simple query
    **/
    function query($query = '')
    {
        if($query == '')
            $this->_result = @mysql_query($this->_query, $this->_conn_id);
        else   
            $this->_result = @mysql_query($query, $this->_conn_id);
            
        if(!$this->_result)
            $this->show_error('Can\'t execute query.' . mysql_error($this->_conn_id));
        return $this->_result;
    }
    
    /**
    * Get how many row is executed.
    **/
    function get_success_rows()
    {
        return @mysql_affected_rows($this->_conn_id);
    }
    
    /**
    * Get number of row is selected.
    **/
    function get_num_rows($resource = NULL)
    {
        return ($resource != NULL)? @mysql_num_rows($resource) : @mysql_num_rows($this->_result);
    }
    
	/**
	 * Description
	 *
	 * @access public
	 */
	function insertid()
	{
		return mysql_insert_id( $this->_conn_id );
	}
    
    /**
     * This method loads the first field of the first row returned by the query.
     *
     * @access    public
     * @return The value returned in the query or null if the query failed.
     */
     function get_result()
     {
         if (!($cur = $this->query())) {
            return null;
        }
        $ret = null;
        if ($row = mysql_fetch_row( $cur )) {
            $ret = $row[0];
        }
        mysql_free_result( $cur );
        return $ret;
     }
     
         /**
    * Fetch a result row as an associative array
    *
    * @access    public
    * @return array
    */
    function get_assoc()
    {
        if (!($cur = $this->query())) {
            return null;
        }
        $ret = null;
        if ($array = mysql_fetch_assoc( $cur )) {
            $ret = $array;
        }
        mysql_free_result( $cur );
        return $ret;
    }
    
        /**
    * This global function loads the first row of a query into an object
    *
    * @access    public
    * @return     object
    */
    function get_object( )
    {
        if (!($cur = $this->query())) {
            return null;
        }
        $ret = null;
        if ($object = mysql_fetch_object( $cur )) {
            $ret = $object;
        }
        mysql_free_result( $cur );
        return $ret;
    }

    /**
    * Load a list of database objects
    *
    * If <var>key</var> is not empty then the returned array is indexed by the value
    * the database key.  Returns <var>null</var> if the query fails.
    *
    * @access    public
    * @param string The field name of a primary key
    * @return array If <var>key</var> is empty as sequential list of returned records.
    */
    function get_object_list( $key='' )
    {
        if (!($cur = $this->query())) {
            return null;
        }
        $array = array();
        while ($row = mysql_fetch_object( $cur )) {
            if ($key) {
                $array[$row->$key] = $row;
            } else {
                $array[] = $row;
            }
        }
        mysql_free_result( $cur );
        return $array;
    }

    /**
     * Description
     *
     * @access    public
     * @return The first row of the query.
     */
    function get_row()
    {
        if (!($cur = $this->query())) {
            return null;
        }
        $ret = null;
        if ($row = mysql_fetch_row( $cur )) {
            $ret = $row;
        }
        mysql_free_result( $cur );
        return $ret;
    }

    /**
    * Load a list of database rows (numeric column indexing)
    *
    * @access public
    * @param string The field name of a primary key
    * @return array If <var>key</var> is empty as sequential list of returned records.
    * If <var>key</var> is not empty then the returned array is indexed by the value
    * the database key.  Returns <var>null</var> if the query fails.
    */
    function get_row_list( $key=null )
    {
        if (!($cur = $this->query())) {
            return null;
        }
        $array = array();
        while ($row = mysql_fetch_row( $cur )) {
            if ($key !== null) {
                $array[$row[$key]] = $row;
            } else {
                $array[] = $row;
            }
        }
        mysql_free_result( $cur );
        return $array;
    }
    
    /**
     * Cover value to string with quote.
     *
     * @access    public
     * @param    string    a string which we want cover to string with quote
     */
    public function nameQuote($value)
    {
    	if (strpos( $value, '.' ) === false){
			return $this->_namequote . $value . $this->_namequote;
		}
		else {
			return $value;
		}
    }
    
	/**
     * Cover value to string with quote.
     *
     * @access    public
     * @param    string    a string which we want cover to string with quote
     */
    public function valueQuote($value)
    {
		return $this->_valuequote . $value . $this->_valuequote;
    }
    
    /**
     * Cover value to string with quote.
     *
     * @access    public
     * @param    array    An array values which we want cover to string with quote
     */
    public function addQuote($arrValues, $single = true)
    {
        if(!is_array($arrValues))
            $this->show_error('Invalid parameter on fixQuote');
         $values = $arrValues;
         foreach($values as $key => $val)
         {
             if(is_string($val))
                 $values[$key] = $this->valueQuote($val);
         }
         return $values;
    }
    
    /**
     * select data from databases with conditions.
     *
     * @access    public
     * @select    array    All fields is selected
     * @from      array    All table which have it's fields are selected
     * @where     array    All conditions
     * @extra     array    All orther keywords
     */
    function selectObject($data)
    {
        if(is_array($data))
        {
            if(isset($data['select']) && isset($data['from']))
            {
                $sql = "SELECT " . $data['select'] . " FROM " . $data['from'];
                if(isset($data['where']))
                    $sql .= " WHERE " . $data['where'];
                if(isset($data['extra']))
                    $sql .= " " . $data['extra'];
                if(isset($data['limit']))
                    $sql .= " LIMIT " . $data['limit'];
                $this->set_query($sql);
                //debug($sql);
                if($this->query())
                {
                    if($this->get_num_rows() > 1)
                        return $this->get_object_list();
                    else 
                        return $this->get_object();
                }
            }
        }
        return false;
    }
    
	/**
	 * Inserts a row into a table based on an objects properties
	 *
	 * @access	public
	 * @param	string	The name of the table
	 * @param	object	An object whose properties match table fields
	 * @param	string	The name of the primary key. If provided the object property is updated.
	 */
	function insertObject( $table, &$object, $primary = NULL )
	{
		$sql = 'INSERT INTO '.$this->nameQuote($table).' ( %s ) VALUES ( %s ) ';
		$fields = array();
		foreach (get_object_vars( $object ) as $k => $v) {
			if (is_array($v) or is_object($v) or $v === NULL) {
				continue;
			}
			if ($k[0] == '_') { // internal field
				continue;
			}
			
			$fields[] = $this->nameQuote( $k );
			$values[] = is_string($v) ? $this->valueQuote( $v ) : (int) $v;
		}
		var_dump(sprintf( $sql, implode( ",", $fields ) ,  implode( ",", $values ) ));
		$this->set_query( sprintf( $sql, implode( ",", $fields ) ,  implode( ",", $values ) ) );
		if (!$this->query()) {
			return false;
		}
		$id = $this->insertid();
		if ($primary && $id) {
			$object->$primary = $id;
		}
		return true;
	}
	
	/**
	 * Description
	 *
	 * @access public
	 * @param	string	The name of the table
	 * @param	object	An object whose properties match table fields
	 * @param	string	Primary key
	 * @param   bool    Update null values
	 */
	function updateObject( $table, &$object, $primary, $null = true )
	{
		$sql = 'UPDATE '.$this->nameQuote($table).' SET %s WHERE %s';
		$tmp = array();
		foreach (get_object_vars( $object ) as $k => $v)
		{
			if( is_array($v) or is_object($v) or $k[0] == '_' ) { 
				continue;
			}
			if( $k == $primary ) { // PK not to be updated
				$where = $primary . '=' . $this->valueQuote( $v );
				continue;
			}
			if ($v === null)
			{
				if ($null) {
					$val = 'NULL';
				} else {
					continue;
				}
			} else {
				$val = is_string($v) ? $this->valueQuote( $v ) : (int) $v;
			}
			$tmp[] = $this->nameQuote( $k ) . '=' . $val;
		}
		$this->setQuery( sprintf( $fmtsql, implode( ",", $tmp ) , $where ) );
		return $this->query();
	}
	
	/**
	 * Load a row into a object based on an objects properties
	 *
	 * @access	public
	 * @param	string	The name of the table
	 * @param	id		Id of an object whose properties match table fields
	 * @param	string	The name of the primary key. If provided the object property is updated.
	 */
	function loadObject( $table, &$object )
	{
		$table 			= $this->nameQuote($table);
		$primary_key 	= $object->key();
		$primary_value	= isset($object->$primary_key) ? intval($object->$primary_key) : null;
		if(is_null($primary_value)) return false;
		
		$data = array(	'select' 	=> '*',
						'from'		=> $table,
						'where'		=> $this->nameQuote($primary_key) . ' = ' . $primary_value,
						'limit'		=> 1 );
		//debug($data);
		$result = $this->selectObject($data);
		if($result)
			return $object->fill(get_object_vars($result));
		return false;
	}
	
	/**
	 * Delete a row in a table.
	 *
	 * @access	public
	 * @param	string	The name of the table
	 * @param	id		Id of an object whose properties match table fields
	 * @param	string	The name of the primary key. If provided the object property is deleted.
	 */
	function deleteObject( $table, &$object )
	{
		$primary_key 	= $object->key();
		$primary_value	= $object->$primary_key;
		
		$sql = 'DELETE FROM '.$this->nameQuote($table).' WHERE ( %s )';
		$this->set_query( sprintf( $sql, $this->nameQuote($primary_key) . ' = ' . $this->valueQuote($primary_value)));
		if (!$this->query()) {
			return false;
		}
		return true;
	}
    
    public function get_model($model_name, $model_type = DIR_COMPONENTS)
    {
    	if($model_type == DIR_MODULES)
    		$class_name = 'ModModel' . ucfirst($model_name);
    	else
    		$class_name = 'Model' . ucfirst($model_name);
    		
    	if(!isset($this->_models[$class_name]))
    	{
	    	BLoader::import( $model_name . '.model', $model_type );
	    	$this->_models[$class_name] = new $class_name();
    	}
    	return $this->_models[$class_name];
    }
	
	public function show_error($msg)
	{
		var_dump($msg);die();
	}
}

?>